/*
 ------------------------------------------------------------------------------
 Copyright (C) 2006-2007 Team Blur.

 This file is part of the Quantum Engine source code.

 The Quantum Engine source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quantum Engine source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quantum Engine source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


#ifndef __R_LOCAL_H__
#define __R_LOCAL_H__


#include "../client/client.h"
#include "r_public.h"
#include "qgl.h"


#define GL_INDEX_TYPE					GL_UNSIGNED_INT

typedef unsigned int		glIndex_t;

typedef struct {
	odVec3					xyz;
	odVec3					normal;
	odVec3					tangents[2];
	odVec2					st;
	byte					color[4];
} glVertex_t;

typedef struct {
	odVec4					xyzw;
} glShadowVertex_t;

/*
 ==============================================================================

 VERTEX BUFFER MANAGER

 ==============================================================================
*/

#define MAX_VERTEX_BUFFERS				4096

typedef struct vertexBuffer_s {
	bool					dynamic;
	int						size;

	int						frameCount;

	uint					bufferId;

	struct vertexBuffer_s *	prev;
	struct vertexBuffer_s *	next;
} vertexBuffer_t;

vertexBuffer_t *	R_AllocVertexBuffer (bool dynamic, const void *data, int size);
void				R_FreeVertexBuffer (vertexBuffer_t *vertexBuffer);

void				R_UpdateVertexBuffer (vertexBuffer_t *vertexBuffer, const void *data, int size, int offset);
void *				R_MapVertexBuffer (vertexBuffer_t *vertexBuffer);
void				R_UnmapVertexBuffer (vertexBuffer_t *vertexBuffer);

void				R_InitVertexBuffers (void);
void				R_ShutdownVertexBuffers (void);

/*
 ==============================================================================

 TEXTURE MANAGER

 ==============================================================================
*/

#define MAX_TEXTURES					8192

typedef enum {
	TF_INTERNAL				= BIT(0),
	TF_NOPICMIP				= BIT(1),
	TF_UNCOMPRESSED			= BIT(2),
	TF_INTENSITY			= BIT(3),
	TF_ALPHA				= BIT(4),
	TF_LIGHTMAP				= BIT(5),
	TF_NORMALMAP			= BIT(6)
} textureFlags_t;

typedef enum {
	TF_DEFAULT,
	TF_NEAREST,
	TF_LINEAR
} textureFilter_t;

typedef enum {
	TW_REPEAT,
	TW_CLAMP,
	TW_CLAMP_TO_ZERO,
	TW_CLAMP_TO_ZERO_ALPHA
} textureWrap_t;

typedef struct texture_s {
	char					name[MAX_OSPATH];

	int						flags;
	textureFilter_t			filter;
	textureWrap_t			wrap;

	bool					isCubeMap;

	int						width;
	int						height;
	int						samples;
	int						size;
	uint					format;
	uint					target;

	int						frameCount;

	uint					textureId;

	struct texture_s *		nextHash;
} texture_t;

texture_t *			R_FindTexture (const char *name, int flags, textureFilter_t filter, textureWrap_t wrap);
texture_t *			R_FindCubeMapTexture (const char *name, int flags, textureFilter_t filter, textureWrap_t wrap, bool cameraSpace);

texture_t *			R_GetTextureByName (const char *name);

void				R_SetTextureParameters (void);

void				R_InitTextures (void);
void				R_ShutdownTextures (void);

/*
 ==============================================================================

 VIDEO MANAGER

 ==============================================================================
*/

#define MAX_VIDEOS						16

typedef struct video_s {
	char					name[MAX_OSPATH];

	fileHandle_t			file;
	int						size;
	int						offset;

	int						frameWidth;
	int						frameHeight;
	int						frameRate;
	byte *					frameBuffer[2];

	int						startTime;
	int						currentFrame;

	byte					data[ROQ_MAX_CHUNK_SIZE + ROQ_CHUNK_HEADER_SIZE];
	byte *					header;

	roqChunk_t				chunk;
	roqQuadVector_t			quadVectors[256];
	roqQuadCell_t			quadCells[256];

	struct video_s *		nextHash;
} video_t;

video_t *			R_PlayVideo (const char *name);
void				R_UpdateVideo (video_t *video, int time);

void				R_InitVideos (void);
void				R_ShutdownVideos (void);

/*
 ==============================================================================

 SHADER MANAGER

 ==============================================================================
*/

#define MAX_SHADERS						256

typedef enum {
	SHADER_VERTEX,
	SHADER_FRAGMENT
} shaderType_t;

typedef struct shader_s {
	char					name[MAX_OSPATH];

	shaderType_t			type;
	int						references;

	bool					compiled;

	uint					shaderId;

	struct shader_s *		nextHash;
} shader_t;

shader_t *			R_FindShader (const char *name, shaderType_t type);

void				R_InitShaders (void);
void				R_ShutdownShaders (void);

/*
 ==============================================================================

 PROGRAM MANAGER

 ==============================================================================
*/

#define MAX_PROGRAMS					128
#define MAX_PROGRAM_UNIFORMS			32

typedef enum {
	UT_VIEW_ORIGIN,
	UT_VIEW_AXIS,
	UT_ENTITY_ORIGIN,
	UT_ENTITY_AXIS,
	UT_SKYBOX_MATRIX,
	UT_PORTALSKY_MATRIX,
	UT_SCREEN_MATRIX,
	UT_XY_SCALE,
	UT_POT_ADJUST,
	UT_LIGHT_SCALE,
	UT_CUSTOM
} uniformType_t;

typedef struct {
	uniformType_t			type;

	char					name[64];
	uint					format;
	int						size;
	int						location;
} uniform_t;

typedef struct program_s {
	char					name[MAX_OSPATH];

	shader_t *				vertexShader;
	shader_t *				fragmentShader;

	int						numUniforms;
	uniform_t *				uniforms;

	bool					linked;

	uint					programId;

	struct program_s *		nextHash;
} program_t;

program_t *			R_FindProgram (shader_t *vertexShader, shader_t *fragmentShader);

uniform_t *			R_GetProgramUniform (program_t *program, const char *name);
int					R_GetProgramUniformLocation (program_t *program, const char *name, uint format, int size);
void				R_SetProgramSampler (program_t *program, uniform_t *uniform, uint unit);
void				R_SetProgramSamplerByName (program_t *program, const char *name, uint unit);

void				R_InitPrograms (void);
void				R_ShutdownPrograms (void);

/*
 ==============================================================================

 MATERIAL TABLE MANAGER

 ==============================================================================
*/

#define MAX_TABLES						1024
#define MAX_TABLE_SIZE					256

typedef struct table_s {
	char					name[MAX_OSPATH];
	int						index;

	bool					clamp;
	bool					snap;

	int						size;
	float *					values;

	struct table_s *		nextHash;
} table_t;

table_t *			R_FindTable (const char *name);

bool				R_ParseTable (script_t *script);

float				R_LookupTable (int index, float lutIndex);

void				R_InitTables (void);
void				R_ShutdownTables (void);

/*
 ==============================================================================

 MATERIAL MANAGER

 ==============================================================================
*/

#define MAX_MATERIALS					4096
#define MAX_STAGES						64

#define MAX_EXPRESSION_OPS				4096
#define MAX_EXPRESSION_REGISTERS		4096

#define MAX_TEXMODS						4

#define MAX_SHADER_PARMS				32
#define MAX_SHADER_MAPS					8

typedef enum {
	MT_GENERIC,
	MT_LIGHT,
	MT_NOMIP
} materialType_t;

typedef enum {
	MC_OPAQUE,
	MC_PERFORATED,
	MC_TRANSLUCENT
} materialCoverage_t;

typedef enum {
	MF_EXTERNAL				= BIT(0),
	MF_DEFAULTED			= BIT(1),
	MF_NOOVERLAYS			= BIT(2),
	MF_NOFOG				= BIT(3),
	MF_NOSHADOWS			= BIT(4),
	MF_NOSELFSHADOW			= BIT(5),
	MF_POLYGONOFFSET		= BIT(6)
} materialFlags_t;

typedef enum {
	SL_AMBIENT,
	SL_BUMP,
	SL_DIFFUSE,
	SL_SPECULAR
} stageLighting_t;

typedef enum {
	SF_POLYGONOFFSET		= BIT(0),
	SF_BLEND				= BIT(1),
	SF_ALPHATEST			= BIT(2),
	SF_IGNOREALPHATEST		= BIT(3),
	SF_MASKRED				= BIT(4),
	SF_MASKGREEN			= BIT(5),
	SF_MASKBLUE				= BIT(6),
	SF_MASKALPHA			= BIT(7)
} stageFlags_t;

typedef enum {
	OP_TYPE_MULTIPLY,
	OP_TYPE_DIVIDE,
	OP_TYPE_MOD,
	OP_TYPE_ADD,
	OP_TYPE_SUBTRACT,
	OP_TYPE_GREATER,
	OP_TYPE_LESS,
	OP_TYPE_GEQUAL,
	OP_TYPE_LEQUAL,
	OP_TYPE_EQUAL,
	OP_TYPE_NOTEQUAL,
	OP_TYPE_AND,
	OP_TYPE_OR,
	OP_TYPE_TABLE
} opType_t;

typedef enum {
	EXP_REGISTER_IDENTITY,
	EXP_REGISTER_SHADERPROGRAMS,
	EXP_REGISTER_SHADERLEVEL,
	EXP_REGISTER_TIME,
	EXP_REGISTER_PARM0,
	EXP_REGISTER_PARM1,
	EXP_REGISTER_PARM2,
	EXP_REGISTER_PARM3,
	EXP_REGISTER_PARM4,
	EXP_REGISTER_PARM5,
	EXP_REGISTER_PARM6,
	EXP_REGISTER_PARM7,
	EXP_REGISTER_GLOBAL0,
	EXP_REGISTER_GLOBAL1,
	EXP_REGISTER_GLOBAL2,
	EXP_REGISTER_GLOBAL3,
	EXP_REGISTER_GLOBAL4,
	EXP_REGISTER_GLOBAL5,
	EXP_REGISTER_GLOBAL6,
	EXP_REGISTER_GLOBAL7,
	EXP_REGISTER_NUM_PREDEFINED
} expRegister_t;

typedef enum {
	LT_GENERIC,
	LT_AMBIENT,
	LT_FOG,
	LT_BLEND
} lightType_t;

typedef enum {
	SORT_BAD,
	SORT_OPAQUE,
	SORT_SKY,
	SORT_DECAL,
	SORT_SEE_THROUGH,
	SORT_BANNER,
	SORT_UNDERWATER,
	SORT_WATER,
	SORT_FARTHEST,
	SORT_FAR,
	SORT_MEDIUM,
	SORT_CLOSE,
	SORT_ADDITIVE,
	SORT_ALMOST_NEAREST,
	SORT_NEAREST,
	SORT_POST_PROCESS
} sort_t;

typedef enum {
	ST_NONE,
	ST_PORTALSKY,
	ST_MIRROR,
	ST_PORTAL,
	ST_REMOTE
} subviewType_t;

typedef enum {
	CT_FRONT_SIDED,
	CT_BACK_SIDED,
	CT_TWO_SIDED
} cullType_t;

typedef enum {
	DFRM_NONE,
	DFRM_EXPAND,
	DFRM_MOVE,
	DFRM_SPRITE,
	DFRM_TUBE,
	DFRM_FLARE
} deform_t;

typedef enum {
	TG_EXPLICIT,
	TG_REFLECT,
	TG_NORMAL,
	TG_SKYBOX,
	TG_PORTALSKY,
	TG_SCREEN
} texGen_t;

typedef enum {
	TM_TRANSLATE,
	TM_SCROLL,
	TM_SCALE,
	TM_CENTERSCALE,
	TM_SHEAR,
	TM_ROTATE
} texMod_t;

typedef enum {
	VC_IGNORE,
	VC_MODULATE,
	VC_INVERSE_MODULATE
} vertexColor_t;

typedef struct {
	opType_t				opType;

	int						a;
	int						b;
	int						c;
} expOp_t;

typedef struct {
	float					stayTime;
	float					fadeTime;

	odVec4					startRGBA;
	odVec4					endRGBA;
} decalInfo_t;

typedef struct {
	uniform_t *				uniform;

	int						registers[4];
} shaderParm_t;

typedef struct {
	texture_t *				texture;
	video_t *				video;
} shaderMap_t;

typedef struct {
	texture_t *				texture;
	video_t *				video;

	texGen_t				texGen;

	int						numTexMods;
	texMod_t				texMods[MAX_TEXMODS];
	int						texModsRegisters[MAX_TEXMODS][2];
} textureStage_t;

typedef struct {
	int						registers[4];

	vertexColor_t			vertexColor;
} colorStage_t;

typedef struct {
	program_t *				program;

	shader_t *				vertexShader;
	shader_t *				fragmentShader;

	int						numShaderParms;
	shaderParm_t			shaderParms[MAX_SHADER_PARMS];

	int						numShaderMaps;
	shaderMap_t				shaderMaps[MAX_SHADER_MAPS];
} shaderStage_t;

typedef struct {
	stageLighting_t			lighting;
	int						flags;

	int						conditionRegister;

	textureStage_t			textureStage;
	colorStage_t			colorStage;
	shaderStage_t			shaderStage;

	float					specularExponent;
	float					specularBrightness;

	uint					blendSrc;
	uint					blendDst;

	int						alphaTestRegister;

	bool					isGlow;
} stage_t;

typedef struct material_s {
	char					name[MAX_OSPATH];
	int						index;

	materialType_t			type;
	materialCoverage_t		coverage;
	int						flags;

	int						conditionRegister;

	lightType_t				lightType;
	texture_t *				lightFalloffImage;

	int						spectrum;

	decalInfo_t				decalInfo;

	sort_t					sort;

	subviewType_t			subviewType;
	int						subviewWidth;
	int						subviewHeight;

	cullType_t				cullType;

	deform_t				deform;
	int						deformRegisters[3];

	bool					hasGlowStages;

	int						numStages;
	int						numAmbientStages;
	stage_t *				stages;

	bool					constantExpressions;

	int						numOps;
	expOp_t *				expressionOps;

	int						numRegisters;
	float *					expressionRegisters;

	struct material_s *		nextHash;
} material_t;

material_t *		R_FindMaterial (const char *name, materialType_t type);

void				R_EvaluateRegisters (material_t *material, float time, const float *entityParms, const float *globalParms);

void				R_InitMaterials (void);
void				R_ShutdownMaterials (void);

/*
 ==============================================================================

 MODEL MANAGER

 ==============================================================================
*/

#define MAX_MODELS						2048

typedef struct {
	odVec3					origin;
	odMat3					axis;

	struct surface_s *		parentSurface;		// Pointer to parent surface for rendering

	int						viewCount;
} foliageInstance_t;

typedef struct surface_s {
	surfaceType_t			type;				// ST_FACE, ST_PATCH, ST_TRISOUP, or ST_FOLIAGE

	material_t *			material;

	odPlane *				plane;				// NULL if non-planar surface

	odBounds				bounds;				// For culling

	int						numIndices;
	glIndex_t *				indices;

	int						numVertices;
	glVertex_t *			vertices;

	int *					neighbors;			// Triangle neighbors for silhouette determination

	odPlane *				facePlanes;			// Triangle plane equations (NULL if planar surface)

	int						numFoliageInstances;
	foliageInstance_t *		foliageInstances;

	float					foliageRadius;
	float					foliageMinDistance;
	float					foliageMaxDistance;

	vertexBuffer_t *		ambientBuffer;		// glVertex_t in write-only vertex buffer memory
	vertexBuffer_t *		shadowBuffer;		// glShadowVertex_t in write-only vertex buffer memory

	int						ambientIndex;		// Index to first surface vertex in ambientBuffer
	int						shadowIndex;		// Index to first surface vertex in shadowBuffer

	int						viewCount;
	int						worldCount;
	int						lightCount;
	int						fragmentCount;
} surface_t;

typedef struct node_s {
	// Common with node and leaf
	bool					isLeaf;				// To differentiate between nodes and leafs

	odBounds				bounds;				// For culling

	struct node_s *			parent;

	int						viewCount;
	int						visCount;

	// Node specific
	struct node_s *			children[2];
	odPlane *				plane;

	// Leaf specific
	int						cluster;
	int						area;

	int						numLeafSurfaces;
	surface_t **			leafSurfaces;
} node_t;

typedef struct {
	odBounds				bounds;				// For culling

	int						numSurfaces;
	surface_t *				surfaces;
} inlineModel_t;

typedef struct {
	char					name[MAX_OSPATH];
	int						size;

	int						numPlanes;
	odPlane *				planes;

	int						numIndices;
	glIndex_t *				indices;

	int						numVertices;
	glVertex_t *			vertices;

	int						numNeighbors;
	int *					neighbors;

	int						numFacePlanes;
	odPlane *				facePlanes;

	int						numFoliageInstances;
	foliageInstance_t *		foliageInstances;

	int						numSurfaces;
	surface_t *				surfaces;

	int						numLeafSurfaces;
	surface_t **			leafSurfaces;

	int						numNodes;
	node_t *				nodes;

	int						numInlineModels;
	inlineModel_t *			inlineModels;
} world_t;

typedef struct {
	material_t *			material;

	odBounds				bounds;				// For culling

	int						numIndices;
	glIndex_t *				indices;

	int						numVertices;
	glVertex_t *			vertices;

	int *					neighbors;			// Triangle neighbors for silhouette determination

	odPlane *				facePlanes;			// Triangle plane equations

	vertexBuffer_t *		ambientBuffer;		// glVertex_t in write-only vertex buffer memory
	vertexBuffer_t *		shadowBuffer;		// glShadowVertex_t in write-only vertex buffer memory

	int						ambientIndex;		// Index to first surface vertex in ambientBuffer
	int						shadowIndex;		// Index to first surface vertex in shadowBuffer
} mdlSurface_t;

typedef struct {
	odBounds				bounds;				// For culling

	int						numSurfaces;
	mdlSurface_t *			surfaces;
} mdlModel_t;

typedef struct {
	int						parent;				// Parent index

	odJointMat				matrix;
} md5Joint_t;

typedef struct {
	odVec3					baseXyz;
	odVec3					baseNormal;
	odVec3					baseTangents[2];

	odVec2					st;

	int						firstWeight;
	int						numWeights;
} md5Vertex_t;

typedef struct {
	int						joint;				// Joint index
	float					jointWeight;

	odVec3					offset;
} md5Weight_t;

typedef struct {
	material_t *			material;

	int						numIndices;
	glIndex_t *				indices;

	int						numVertices;
	md5Vertex_t *			vertices;

	int						numWeights;
	md5Weight_t *			weights;

	int *					neighbors;			// Triangle neighbors, calculated on load
} md5Surface_t;

typedef struct {
	int						numJoints;
	md5Joint_t *			joints;

	int						numSurfaces;
	md5Surface_t *			surfaces;
} md5Model_t;

typedef enum {
	MODEL_BAD,
	MODEL_INLINE,
	MODEL_MDL,
	MODEL_MD5
} modelType_t;

typedef struct model_s {
	char					name[MAX_OSPATH];
	modelType_t				type;

	void *					data;
	int						size;

	struct model_s *		nextHash;
} model_t;

void				R_LoadInlineModel (int index, void *data);

//mdlModel_t *		R_InstantiateDynamicModel (struct entity_s *entity, bool cacheAmbient, bool cacheShadow);
void				R_ClearDynamicModelInstance (struct entity_s *entity);

void				R_InitModels (void);
void				R_ShutdownModels (void);

/*
 ==============================================================================

 LIGHT MANAGER

 ==============================================================================
*/

typedef struct lightNode_s {
	node_t *				leaf;

	int						numLeafSurfaces;
	surface_t **			leafSurfaces;

	struct lightNode_s *	next;
} lightNode_t;

typedef struct {
	bool					computed;

	odVec3					origin;

	odVec3					corners[8];
	odPlane					frustum[6];

	odVec3					planeNormal;
	float					planeDist;

	odMat4					projectionMatrix;
	odMat4					modelviewMatrix;

	const byte *			pvs;
	int						area;

	// Precompiled interactions and shadows
	bool					precompiled;

	lightNode_t *			interactionNodes;
	lightNode_t *			shadowNodes;
} lightData_t;

typedef struct {
	renderLight_t			l;

	lightData_t				data;
} compiledLight_t;

/*
 ==============================================================================

 SCENE MANAGER

 ==============================================================================
*/

typedef struct entity_s {
	bool					active;
	int						index;
	int						viewCount;

	renderEntity_t			e;

	mdlModel_t *			instance;

	struct entity_s *		prev;
	struct entity_s *		next;
} entity_t;

typedef struct light_s {
	bool					active;
	int						index;
	int						viewCount;

	renderLight_t			l;

	lightData_t				data;

	struct light_s *		prev;
	struct light_s *		next;
} light_t;

typedef struct particle_s {
	bool					active;
	int						index;
	int						viewCount;

	renderParticle_t		p;

	struct particle_s *		prev;
	struct particle_s *		next;
} particle_t;

typedef struct decal_s {
	float					startTime;
	float					endTime;

	material_t *			material;

	entity_t *				parentEntity;		// Parent entity for culling
	surface_t *				parentSurface;		// Parent surface for culling

	model_t *				baseModel;
	int						baseSurface;
	int *					baseTriangles;
	int *					baseVertices;

	int						numIndices;
	glIndex_t *				indices;

	int						numVertices;
	glVertex_t *			vertices;

	struct decal_s *		prev;
	struct decal_s *		next;
} decal_t;

typedef struct scene_s {
	bool					inUse;

	int						maxEntities;
	entity_t *				entities;

	int						maxLights;
	light_t *				lights;

	int						maxParticles;
	particle_t *			particles;

	int						maxDecals;
	decal_t *				decals;

	// Active lists
	entity_t				activeEntity;
	light_t					activeLight;
	particle_t				activeParticle;
	decal_t					activeDecal;

	// Free lists
	entity_t *				freeEntity;
	light_t *				freeLight;
	particle_t *			freeParticle;
	decal_t *				freeDecal;

	// World entity for world rendering
	entity_t *				worldEntity;

	// Compiled lights
	bool					compiledLights;
	compiledLight_t *		compiledLightsList[MAX_ENTITIES];
} scene_t;

/*
 ==============================================================================

 GL STATE MANAGER

 ==============================================================================
*/

#define MAX_TEXTURE_UNITS				8

typedef struct {
	odMat4					projectionMatrix;
	odMat4					modelviewMatrix;
	odMat4					textureMatrix[MAX_TEXTURE_UNITS];

	uint					activeUnit;
	uint					activeTarget[MAX_TEXTURE_UNITS];

	uint					textureId[MAX_TEXTURE_UNITS];
	int						texEnv[MAX_TEXTURE_UNITS];
	int						texGen[MAX_TEXTURE_UNITS][4];

	bool					cullFace;
	bool					polygonOffsetFill;
	bool					blend;
	bool					alphaTest;
	bool					depthTest;
	bool					stencilTest;
	bool					textureGen[MAX_TEXTURE_UNITS][4];

	uint					cullMode;
	float					offsetFactor;
	float					offsetUnits;
	uint					blendSrc;
	uint					blendDst;
	uint					alphaFunc;
	float					alphaRef;
	uint					depthFunc;
	uint					stencilFunc;
	int						stencilRef;
	uint					stencilRefMask;
	uint					stencilFail;
	uint					stencilZFail;
	uint					stencilZPass;

	bool					colorMask[4];
	bool					depthMask;
	uint					stencilMask;

	float					depthMin;
	float					depthMax;

	uint					bufferId;
} glState_t;

void				GL_LoadIdentity (uint mode);
void				GL_LoadMatrix (uint mode, const odMat4 &m);
void				GL_SelectTexture (uint unit);
void				GL_EnableTexture (uint target);
void				GL_DisableTexture (void);
void				GL_BindTexture (texture_t *texture);
void				GL_TexEnv (int texEnv);
void				GL_TexGen (uint texCoord, int texGen);
void				GL_Enable (uint cap);
void				GL_Disable (uint cap);
void				GL_CullFace (uint mode);
void				GL_PolygonOffset (float factor, float units);
void				GL_BlendFunc (uint src, uint dst);
void				GL_AlphaFunc (uint func, float ref);
void				GL_DepthFunc (uint func);
void				GL_StencilFunc (uint func, int ref, uint mask);
void				GL_StencilOp (uint fail, uint zFail, uint zPass);
void				GL_ColorMask (bool red, bool green, bool blue, bool alpha);
void				GL_DepthMask (bool mask);
void				GL_StencilMask (uint mask);
void				GL_DepthRange (float min, float max);
void				GL_BindVertexBuffer (vertexBuffer_t *vertexBuffer);

void				GL_SetDefaultState (void);
void				GL_CheckForErrors (void);

/*
 ==============================================================================

 DRAW MESHES

 ==============================================================================
*/

#define MAX_DRAW_MESHES					131072
#define MAX_DRAW_POST_PROCESS_MESHES	2048

#define SORT_SHIFT_MATERIAL				20
#define SORT_SHIFT_ENTITY				8
#define SORT_SHIFT_TYPE					4

typedef void				mesh_t;

typedef enum {
	MESH_BAD,
	MESH_SURFACE,
	MESH_MODEL,
	MESH_FOLIAGE,
	MESH_SPRITE,
	MESH_BEAM,
	MESH_PARTICLE,
	MESH_DECAL,
} meshType_t;

typedef struct {
	uint					sort;
	mesh_t *				mesh;
} drawMesh_t;

void				R_SortDrawMeshes (void);
void				R_AddDrawMesh (meshType_t type, mesh_t *mesh, material_t *material, entity_t *entity);

void				R_DecomposeSort (scene_t *scene, uint sort, material_t **material, entity_t **entity, meshType_t *type, bool *caps);

/*
 ==============================================================================

 DRAW LIGHTS

 ==============================================================================
*/

#define MAX_DRAW_LIGHTS					2048
#define MAX_DRAW_FOG_LIGHTS				256

typedef struct {
	lightData_t				data;

	material_t *			material;
	float					materialParms[MAX_MATERIAL_PARMS];

	int						scissorX;
	int						scissorY;
	int						scissorWidth;
	int						scissorHeight;

	float					depthMin;
	float					depthMax;

	bool					castShadows;

	int						numInteractionMeshes[2];
	drawMesh_t *			interactionMeshes[2];

	int						numShadowMeshes[2];
	drawMesh_t *			shadowMeshes[2];
} drawLight_t;

void				R_FreeLightMemory (void);

/*
 ==============================================================================

 FRONT-END

 ==============================================================================
*/

#define MAX_RENDER_SCENES				8

#define MAX_RENDER_CROPS				8

#define CULL_OUT						-1

typedef struct {
	int						numDrawMeshes;
	int						firstDrawMesh;
	drawMesh_t *			drawMeshes;

	int						numDrawPostProcessMeshes;
	int						firstDrawPostProcessMesh;
	drawMesh_t *			drawPostProcessMeshes;

	int						numDrawLights;
	int						firstDrawLight;
	drawLight_t *			drawLights;

	int						numDrawFogLights;
	int						firstDrawFogLight;
	drawLight_t *			drawFogLights;
} view_t;

typedef struct {
	bool					primaryView;
	int						viewType;

	bool					portalSkyVisible;
	material_t *			portalSkyMaterial;
	entity_t *				portalSkyEntity;

	int						viewportX;
	int						viewportY;
	int						viewportWidth;
	int						viewportHeight;

	odPlane					frustum[5];

	odMat4					projectionMatrix;
	odMat4					modelviewMatrix;
	odMat4					mvpMatrix;
	odMat4					skyBoxMatrix;
	odMat4					portalSkyMatrix;
	odMat4					screenMatrix;

	// Draw mesh lists
	int						numDrawMeshes;
	drawMesh_t *			drawMeshes;

	int						numDrawPostProcessMeshes;
	drawMesh_t *			drawPostProcessMeshes;

	// Draw light lists
	int						numDrawLights;
	drawLight_t *			drawLights;

	int						numDrawFogLights;
	drawLight_t *			drawFogLights;
} viewParms_t;

typedef struct {
	int						viewType;

	material_t *			material;
	entity_t *				entity;

	renderView_t			renderView;

	odVec3					pvsOrigin;
	odVec4					clipPlane;
} subviewParms_t;

typedef struct {
	int						width;
	int						height;

	float					xScale;
	float					yScale;
} crop_t;

typedef struct {
	scene_t *				scene;

	renderView_t			renderView;
} primaryView_t;

typedef struct {
	int						cullIn;
	int						cullClip;
	int						cullOut;

	int						entityUpdates;
	int						lightUpdates;
	int						particleUpdates;

	int						leafs;
	int						leafSurfaces;
	int						leafFoliages;

	int						particles;
	int						decals;

	int						entities;
	int						entitiesInteraction;
	int						entitiesShadow;

	int						meshes;
	int						meshesInteraction;
	int						meshesShadow;

	int						interactionsSLight;
	int						interactionsDLight;
	int						interactionsSFog;
	int						interactionsDFog;

	int						shadowsSZPass;
	int						shadowsDZPass;
	int						shadowsSZFail;
	int						shadowsDZFail;

	int						lights;
	int						lightsStatic;
	int						lightsDynamic;

	int						dynamicIndices;
	int						dynamicVertices;
	int						dynamicMD5;
	int						dynamicFoliages;
	int						dynamicSprites;
	int						dynamicBeams;
	int						dynamicParticles;
	int						dynamicDecals;

	int						deformIndices;
	int						deformVertices;
	int						deformExpands;
	int						deformMoves;
	int						deformSprites;
	int						deformTubes;
	int						deformFlares;

	int						views;
	int						draws;
	int						indices;
	int						vertices;
	int						shadowIndices;
	int						shadowVertices;

	int						staticBuffers;
	int						staticBufferBytes;
	int						dynamicBuffers;
	int						dynamicBufferBytes;

	int						textures;
	int						textureBytes;

	int						copyToTextures;
	int						copyToTexturePixels;
	int						dynamicTextures;
	int						dynamicTexturePixels;

	float					overdraw;
	float					overdrawShadows;
	float					overdrawLights;
} performanceCounters_t;

typedef struct {
	// Frame time in milliseconds
	int						frameTime;

	// Counters
	int						frameCount;
	int						viewCount;
	int						visCount;
	int						worldCount;
	int						lightCount;
	int						fragmentCount;

	// View cluster
	int						viewCluster;

	// Area bits
	byte					areaBits[BSP_MAX_AREAS/8];

	// Current scene
	scene_t *				scene;

	// Current render view
	renderView_t			renderView;

	// Current view/subview parms
	viewParms_t				viewParms;
	subviewParms_t			subviewParms;

	// View mesh and light lists
	view_t					view;

	// Render scenes
	scene_t *				renderScenes[MAX_RENDER_SCENES];

	// Render crops
	crop_t					renderCrops[MAX_RENDER_CROPS];
	int						currentRenderCrop;

	// Environment shot rendering
	bool					envShotRendering;
	int						envShotSize;

	// Some functions need a copy of the primary view
	bool					primaryViewAvailable;
	primaryView_t			primaryView;

	// The following fields can be used safely by the back-end
	performanceCounters_t	pc;

	world_t *				world;

	texture_t *				defaultTexture;
	texture_t *				whiteTexture;
	texture_t *				blackTexture;
	texture_t *				flatTexture;
	texture_t *				attenuationTexture;
	texture_t *				noAttenuationTexture;
	texture_t *				falloffTexture;
	texture_t *				noFalloffTexture;
	texture_t *				fogTexture;
	texture_t *				fogEnterTexture;
	texture_t *				quadraticTexture;
	texture_t *				cinematicTexture;
	texture_t *				portalSkyTexture;
	texture_t *				subviewTexture;
	texture_t *				bloomTexture;
	texture_t *				scratchTexture;
	texture_t *				accumTexture;
	texture_t *				currentRenderTexture;

	program_t *				ambientLightProgram;
	program_t *				interactionProgram;
	program_t *				shadowProgram;
	program_t *				bloomProgram;

	material_t *			defaultMaterial;
	material_t *			defaultPointLightMaterial;
	material_t *			defaultProjectedLightMaterial;

	material_t *			sortedMaterials[MAX_MATERIALS];

	byte					gammaTable[256];
} trGlobals_t;

extern trGlobals_t			tr;

extern glConfig_t			glConfig;

extern cvar_t *				r_logFile;
extern cvar_t *				r_clear;
extern cvar_t *				r_clearColor;
extern cvar_t *				r_frontBuffer;
extern cvar_t *				r_screenFraction;
extern cvar_t *				r_portalSkyOnly;
extern cvar_t *				r_subviewOnly;
extern cvar_t *				r_lockVisibility;
extern cvar_t *				r_zNear;
extern cvar_t *				r_zFar;
extern cvar_t *				r_offsetFactor;
extern cvar_t *				r_offsetUnits;
extern cvar_t *				r_shadowOffsetFactor;
extern cvar_t *				r_shadowOffsetUnits;
extern cvar_t *				r_colorMipLevels;
extern cvar_t *				r_singleMaterial;
extern cvar_t *				r_singleEntity;
extern cvar_t *				r_singleLight;
extern cvar_t *				r_singleParticle;
extern cvar_t *				r_showCluster;
extern cvar_t *				r_showCull;
extern cvar_t *				r_showUpdates;
extern cvar_t *				r_showScene;
extern cvar_t *				r_showLeafs;
extern cvar_t *				r_showEntities;
extern cvar_t *				r_showMeshes;
extern cvar_t *				r_showInteractions;
extern cvar_t *				r_showShadows;
extern cvar_t *				r_showLights;
extern cvar_t *				r_showDynamic;
extern cvar_t *				r_showDeforms;
extern cvar_t *				r_showPrimitives;
extern cvar_t *				r_showVertexBuffers;
extern cvar_t *				r_showTextureUsage;
extern cvar_t *				r_showRenderToTexture;
extern cvar_t *				r_showBloom;
extern cvar_t *				r_showDepth;
extern cvar_t *				r_showOverdraw;
extern cvar_t *				r_showTris;
extern cvar_t *				r_showNormals;
extern cvar_t *				r_showTextureVectors;
extern cvar_t *				r_showTangentSpace;
extern cvar_t *				r_showVertexColors;
extern cvar_t *				r_showBatchSize;
extern cvar_t *				r_showSkeletons;
extern cvar_t *				r_showModelBounds;
extern cvar_t *				r_showShadowCount;
extern cvar_t *				r_showShadowTris;
extern cvar_t *				r_showShadowVolumes;
extern cvar_t *				r_showShadowSilhouettes;
extern cvar_t *				r_showLightCount;
extern cvar_t *				r_showLightVolumes;
extern cvar_t *				r_showLightScissors;
extern cvar_t *				r_skipVisibility;
extern cvar_t *				r_skipSuppress;
extern cvar_t *				r_skipCulling;
extern cvar_t *				r_skipInteractionCulling;
extern cvar_t *				r_skipShadowCulling;
extern cvar_t *				r_skipShadowProjectionCulling;
extern cvar_t *				r_skipShadowCapsCulling;
extern cvar_t *				r_skipLightCulling;
extern cvar_t *				r_skipUpdates;
extern cvar_t *				r_skipBatching;
extern cvar_t *				r_skipEntities;
extern cvar_t *				r_skipLights;
extern cvar_t *				r_skipParticles;
extern cvar_t *				r_skipDecals;
extern cvar_t *				r_skipFoliage;
extern cvar_t *				r_skipPrecompiledInteractions;
extern cvar_t *				r_skipPrecompiledShadows;
extern cvar_t *				r_skipExpressions;
extern cvar_t *				r_skipConstantExpressions;
extern cvar_t *				r_skipDeforms;
extern cvar_t *				r_skipAmbient;
extern cvar_t *				r_skipBump;
extern cvar_t *				r_skipDiffuse;
extern cvar_t *				r_skipSpecular;
extern cvar_t *				r_skipShadows;
extern cvar_t *				r_skipInteractions;
extern cvar_t *				r_skipFogLights;
extern cvar_t *				r_skipBlendLights;
extern cvar_t *				r_skipTranslucent;
extern cvar_t *				r_skipPostProcess;
extern cvar_t *				r_skipScissors;
extern cvar_t *				r_skipDepthBounds;
extern cvar_t *				r_skipPortalSky;
extern cvar_t *				r_skipSubviews;
extern cvar_t *				r_skipVideos;
extern cvar_t *				r_skipCopyToTextures;
extern cvar_t *				r_skipDynamicTextures;
extern cvar_t *				r_skipRender;
extern cvar_t *				r_skipRenderContext;
extern cvar_t *				r_skipFrontEnd;
extern cvar_t *				r_skipBackEnd;
extern cvar_t *				r_glDriver;
extern cvar_t *				r_ignoreGLErrors;
extern cvar_t *				r_multiSamples;
extern cvar_t *				r_alphaToCoverage;
extern cvar_t *				r_swapInterval;
extern cvar_t *				r_mode;
extern cvar_t *				r_fullscreen;
extern cvar_t *				r_customWidth;
extern cvar_t *				r_customHeight;
extern cvar_t *				r_displayRefresh;
extern cvar_t *				r_gamma;
extern cvar_t *				r_brightness;
extern cvar_t *				r_finish;
extern cvar_t *				r_vertexBuffers;
extern cvar_t *				r_bloom;
extern cvar_t *				r_bloomContrast;
extern cvar_t *				r_bloomMagnitude;
extern cvar_t *				r_bloomIntensity;
extern cvar_t *				r_lightScale;
extern cvar_t *				r_lightDetailLevel;
extern cvar_t *				r_shaderPrograms;
extern cvar_t *				r_shaderDetailLevel;
extern cvar_t *				r_roundTexturesDown;
extern cvar_t *				r_maxTextureSize;
extern cvar_t *				r_compressTextures;
extern cvar_t *				r_textureFilter;
extern cvar_t *				r_textureLODBias;
extern cvar_t *				r_textureAnisotropy;

node_t *			R_PointInLeaf (const odVec3 &point);

int					R_CullBounds (const odBounds &bounds, int planeBits);
int					R_CullEntityBounds (const odBounds &bounds, int planeBits, entity_t *entity);
int					R_CullSphere (const odVec3 &center, float radius, int planeBits);
int					R_CullEntitySphere (const odVec3 &center, float radius, int planeBits, entity_t *entity);

void				R_AddRenderViewCommand (bool bloom);
void				R_AddRenderBloomCommand (void);
void				R_AddCompositeBloomCommand (void);

void				R_AddWorld (void);
void				R_AddInlineModel (entity_t *entity);
void				R_AddMDLModel (entity_t *entity);
//void				R_AddMD5Model (entity_t *entity);
void				R_AddSprite (entity_t *entity);
void				R_AddBeam (entity_t *entity);
void				R_AddEntities (void);
void				R_AddParticles (void);
void				R_AddDecals (void);
void				R_AddLights (void);

void				R_SetupSubview (material_t *material, entity_t *entity, odPlane *plane);

void				R_RenderView (void);
void				R_ResetView (void);

void				R_SetGamma (void);

bool				R_GetVideoModeInfo (int mode, int *width, int *height);

/*
 ==============================================================================

 BACK-END

 ==============================================================================
*/

#define MAX_RENDER_COMMANDS				0x80000

#define MAX_INDICES						8192 * 3
#define MAX_VERTICES					4096

#define MAX_SHADOW_INDICES				MAX_INDICES * 8
#define MAX_SHADOW_VERTICES				MAX_VERTICES * 2

#define POINTER_XYZ(ptr)				((char *)(ptr) + 0)
#define POINTER_NORMAL(ptr)				((char *)(ptr) + 12)
#define POINTER_TANGENT0(ptr)			((char *)(ptr) + 24)
#define POINTER_TANGENT1(ptr)			((char *)(ptr) + 36)
#define POINTER_ST(ptr)					((char *)(ptr) + 48)
#define POINTER_COLOR(ptr)				((char *)(ptr) + 56)

#define POINTER_XYZW(ptr)				((char *)(ptr) + 0)

typedef enum {
	RC_RENDER_VIEW,
	RC_RENDER_BLOOM,
	RC_COMPOSITE_BLOOM,
	RC_CAPTURE_RENDER,
	RC_UPDATE_TEXTURE,
	RC_SET_COLOR,
	RC_STRETCH_PIC,
	RC_SHEARED_PIC,
	RC_RENDER_SIZE,
	RC_SET_BUFFERS,
	RC_SWAP_BUFFERS,
	RC_END_OF_LIST
} renderCommand_t;

typedef struct {
	byte *					data;
	int						size;
	bool					overflowed;
} renderCommandList_t;

typedef struct {
	int						colorScale;
	int						colorBias;
	int						bumpMatrix;
	int						diffuseMatrix;
	int						lightMatrix;
	int						diffuseColor;
} ambientLightParms_t;

typedef struct {
	int						viewOrigin;
	int						lightOrigin;
	int						colorScale;
	int						colorBias;
	int						bumpMatrix;
	int						diffuseMatrix;
	int						specularMatrix;
	int						lightMatrix;
	int						diffuseColor;
	int						specularColor;
	int						specularExponent;
	int						specularBrightness;
} interactionParms_t;

typedef struct {
	int						lightOrigin;
} shadowParms_t;

typedef struct {
	int						texCoordOffset;
	int						xyScale;
} bloomParms_t;

typedef struct {
	bool					primaryView;
	int						viewType;

	bool					bloom;

	int						x;
	int						y;
	int						width;
	int						height;

	odVec3					origin;
	odMat3					axis;

	odMat4					projectionMatrix;
	odMat4					modelviewMatrix;
	odMat4					skyBoxMatrix;
	odMat4					portalSkyMatrix;
	odMat4					screenMatrix;
} renderViewParms_t;

typedef struct {
	odVec3					viewOrigin;
	odMat3					viewAxis;
	odMat4					viewMatrix;

	odVec3					lightOrigin;
	odMat4					lightMatrix;
} renderLocalParms_t;

typedef struct {
	int						commandId;

	float					time;
	float					materialParms[MAX_MATERIAL_PARMS];

	scene_t *				scene;

	renderViewParms_t		viewParms;

	int						numDrawMeshes;
	drawMesh_t *			drawMeshes;

	int						numDrawPostProcessMeshes;
	drawMesh_t *			drawPostProcessMeshes;

	int						numDrawLights;
	drawLight_t *			drawLights;

	int						numDrawFogLights;
	drawLight_t *			drawFogLights;
} renderViewCommand_t;

typedef struct {
	int						commandId;
} renderBloomCommand_t;

typedef struct {
	int						commandId;
} compositeBloomCommand_t;

typedef struct {
	int						commandId;

	texture_t *				texture;
} captureRenderCommand_t;

typedef struct {
	int						commandId;

	texture_t *				texture;

	const byte *			image;
	int						width;
	int						height;
} updateTextureCommand_t;

typedef struct {
	int						commandId;

	odVec4					color;
} setColorCommand_t;

typedef struct {
	int						commandId;

	float					x;
	float					y;
	float					w;
	float					h;
	float					s1;
	float					t1;
	float					s2;
	float					t2;

	material_t *			material;
} stretchPicCommand_t;

typedef struct {
	int						commandId;

	float					x;
	float					y;
	float					w;
	float					h;
	float					s1;
	float					t1;
	float					s2;
	float					t2;
	float					xShear;
	float					yShear;

	material_t *			material;
} shearedPicCommand_t;

typedef struct {
	int						commandId;

	int						width;
	int						height;
} renderSizeCommand_t;

typedef struct {
	int						commandId;
} setBuffersCommand_t;

typedef struct {
	int						commandId;
} swapBuffersCommand_t;

typedef struct {
	// General state
	bool					overlay;
	bool					debugTools;

	byte					color[4];

	float					time;
	float					materialParms[MAX_MATERIAL_PARMS];

	int						renderWidth;
	int						renderHeight;

	odVec2					xyScale;
	odVec2					potAdjust;

	// Render commands
	renderCommandList_t		commandList;

	// Program uniforms
	ambientLightParms_t		ambientLightParms;
	interactionParms_t		interactionParms;
	shadowParms_t			shadowParms;
	bloomParms_t			bloomParms;

	// Scene
	scene_t *				scene;

	// View parms
	renderViewParms_t		viewParms;

	// Local parms
	renderLocalParms_t		localParms;

	// Light state
	drawLight_t *			light;
	material_t *			lightMaterial;
	stage_t *				lightStage;

	// Batch state
	material_t *			material;
	entity_t *				entity;

	bool					shadowVolume;
	bool					shadowCaps;

	vertexBuffer_t *		vertexBuffer;
	void *					vertexPointer;

	// Render function for current batch
	void					(*renderBatch)(void);

	// Index and vertex arrays
	int						numIndices;
	int						numVertices;

	glIndex_t *				indices;
	glVertex_t *			vertices;

	glIndex_t *				shadowIndices;
	glShadowVertex_t *		shadowVertices;
} backEndState_t;

extern backEndState_t		backEnd;

// Geometry batching
void				RB_CheckOverflow (int numIndices, int numVertices, int maxIndices, int maxVertices);

void				RB_BeginBatch (material_t *material, entity_t *entity, bool shadowVolume, bool shadowCaps);
void				RB_EndBatch (void);

void				RB_BatchMesh (meshType_t type, mesh_t *mesh);
void				RB_BatchMeshShadow (meshType_t type, mesh_t *mesh);

// Rendering
void				RB_FillDepthBuffer (int numDrawMeshes, drawMesh_t *drawMeshes);
void				RB_RenderMaterialPasses (int numDrawMeshes, drawMesh_t *drawMeshes, bool postProcess);
void				RB_RenderLights (int numDrawLights, drawLight_t *drawLights);
void				RB_RenderFogLights (int numDrawLights, drawLight_t *drawLights);

void				RB_RenderOverlayMaterial (void);

// Debug rendering
void				RB_RenderDebugTools (const renderViewCommand_t *cmd);

// Material setup
void				RB_Deform (void);

void				RB_MultiplyTextureMatrix (material_t *material, textureStage_t *textureStage, odMat4 &matrix);

void				RB_SetupTextureStage (textureStage_t *textureStage);
void				RB_CleanupTextureStage (textureStage_t *textureStage);
void				RB_SetupColorStage (colorStage_t *colorStage);
void				RB_CleanupColorStage (colorStage_t *colorStage);
void				RB_SetupShaderStage (shaderStage_t *shaderStage);
void				RB_CleanupShaderStage (shaderStage_t *shaderStage);

void				RB_SetMaterialState (void);
void				RB_SetStageState (stage_t *stage);

void				RB_CopyFrameBuffer (texture_t *texture);

// Misc rendering utilities
void				RB_SetEntityState (entity_t *entity);
void				RB_SetLightState (entity_t *entity, drawLight_t *light, material_t *material, stage_t *stage);

void				RB_DrawElements (void);

// Main back-end interface.
// These should be the only functions ever called by the front-end.
void				RB_ExecuteRenderCommands (const void *data);

void				RB_InitBackEnd (void);
void				RB_ShutdownBackEnd (void);

/*
 ==============================================================================

 IMPLEMENTATION SPECIFIC FUNCTIONS

 ==============================================================================
*/

#ifdef _WIN32

#define GL_DRIVER_OPENGL				"OpenGL32"

#define GLImp_SetDeviceGammaRamp		GLW_SetDeviceGammaRamp
#define GLImp_ActivateContext			GLW_ActivateContext
#define	GLImp_SwapBuffers				GLW_SwapBuffers
#define GLImp_Init						GLW_Init
#define GLImp_Shutdown					GLW_Shutdown

void				GLW_SetDeviceGammaRamp (const byte *gammaTable);
void				GLW_ActivateContext (bool active);
void				GLW_SwapBuffers (void);
void				GLW_Init (void);
void				GLW_Shutdown (void);

#else

#error "GLImp not available for this platform"

#endif


#endif	// __R_LOCAL_H__
